package Ms

import (
	"fmt"
	"db2s/ETL"
	"db2s/global"
	"db2s/parDef"
	"db2s/ref"
	"strings"
)

func (cm ColumnMe) Result(object string) global.Return {
	switch object {
	default:
		return global.Return{}
	}
}
func (cm ColumnMe) Set(parameter string, value any) (err error) {
	return ref.UpdateStructJsonValue(cm, parameter, value)
}
func (cm ColumnMe) Comment(parameter parDef.Parameter) (result global.Return, err error) {
	var event = "[Comment]"
	var execSql []string
	execSql = append(execSql, fmt.Sprintf("SELECT "+
		"c.name AS [columnName], \n"+
		"ep.value AS [columnComment] \n"+
		"FROM \n"+
		"sys.columns AS c \n"+
		"JOIN \n"+
		"sys.tables AS t ON c.object_id = t.object_id \n"+
		"JOIN \n"+
		"sys.schemas AS s ON t.schema_id = s.schema_id \n"+
		"LEFT JOIN \n"+
		"sys.extended_properties AS ep ON ep.major_id = t.object_id \n"+
		"AND ep.minor_id = c.column_id \n"+
		"AND ep.name = 'MS_Description' \n"+
		"WHERE \n"+
		"s.name = '%v' \n"+
		"AND t.name = '%v' \n", parameter.Object.Schema, parameter.Object.Table))
	if result, err = forExecQuerySql(event, parameter, ETL.SMap, execSql); err != nil {
		err = ref.ErrAddPrintf("Comment", err)
		return
	}
	if result.Result == nil {
		return
	}
	var p = make(map[string]string)
	for _, vv := range result.Result.([]map[string]any) {
		pp := mapNullActive(vv)
		column, ok1 := pp["columnName"]
		comment, ok2 := pp["columnComment"]
		if ok1 && ok2 {
			p[fmt.Sprintf("%v", column)] = fmt.Sprintf("%v", comment)
		}
	}
	result.Result = p
	return
}
func (cm ColumnMe) LobMeta(parameter parDef.Parameter) (result global.Return, err error) {
	var event = "[LobMeta]"
	var execSql []string
	execSql = append(execSql, fmt.Sprintf("SELECT "+
		"c.name AS [columnName], \n"+
		"t.name AS [columnType] \n"+
		"FROM \n"+
		"sys.columns AS c \n"+
		"JOIN \n"+
		"sys.tables AS t ON c.object_id = t.object_id \n"+
		"JOIN \n"+
		"sys.schemas AS s ON t.schema_id = s.schema_id \n"+
		"JOIN \n"+
		"sys.types AS ty ON c.user_type_id = ty.user_type_id \n"+
		"WHERE \n"+
		"s.name = '%v' \n"+
		"AND t.name = '%v' \n"+
		"AND ty.name IN ('varbinary', 'xml')", parameter.Object.Schema, parameter.Object.Table))
	if result, err = forExecQuerySql(event, parameter, ETL.SMap, execSql); err != nil {
		err = ref.ErrAddPrintf("LobMeta", err)
		return
	}
	if result.Result == nil {
		return
	}
	var p = make(map[string]string)
	for _, vv := range result.Result.([]map[string]any) {
		pp := mapNullActive(vv)
		column, ok1 := pp["columnName"]
		colType, ok2 := pp["columnType"]
		if ok1 && ok2 {
			p[fmt.Sprintf("%v", column)] = fmt.Sprintf("%v", colType)
		}
	}
	result.Result = p
	return
}
func (cm ColumnMe) BigVarcharMeta(parameter parDef.Parameter) (result global.Return, err error) {
	var event = "[BigVarcharMeta]"
	var execSql []string
	execSql = append(execSql, fmt.Sprintf("SELECT \n    "+
		"COLUMN_NAME AS [columnName], \n    "+
		"CONCAT(DATA_TYPE, '(', CHARACTER_MAXIMUM_LENGTH, ')') AS [columnType] \n"+
		"FROM \n    "+
		"INFORMATION_SCHEMA.COLUMNS \n"+
		"WHERE \n\t\t"+
		"TABLE_SCHEMA = '%v' AND\n    "+
		"TABLE_NAME = '%v' AND \n    "+
		"DATA_TYPE in('varchar','nvarchar') AND \n    "+
		"CHARACTER_MAXIMUM_LENGTH > %v",
		parameter.Object.Schema,
		parameter.Object.Table,
		1000))
	if result, err = forExecQuerySql(event, parameter, ETL.SMap, execSql); err != nil {
		err = ref.ErrAddPrintf("BigVarcharMeta", err)
		return
	}
	if result.Result == nil {
		return
	}
	var p = make(map[string]string)
	for _, vv := range result.Result.([]map[string]any) {
		pp := mapNullActive(vv)
		column, ok1 := pp["columnName"]
		colType, ok2 := pp["columnType"]
		if ok1 && ok2 {
			p[fmt.Sprintf("%v", column)] = fmt.Sprintf("%v", colType)
		}
	}
	result.Result = p
	return
}

func (cm ColumnMe) MapConversionMeta() {

}

func (cm ColumnMe) Meta(parameter parDef.Parameter) (result global.Return, err error) {
	var event = "[Meta]"
	var res []parDef.ColumnMeta
	var execSql []string
	execSql = append(execSql, fmt.Sprintf("SELECT \n"+
		"	isc.table_schema AS databaseName, \n"+
		"	isc.table_name AS tableName, \n"+
		"	isc.column_name AS columnName, \n"+
		"	isc.data_type as dataType, \n"+
		"	CAST(sc.precision AS VARCHAR ) as dataPrecision, \n"+
		"	CAST(sc.scale AS VARCHAR ) as dataScale, \n"+
		"	CAST(sc.max_length AS VARCHAR ) as dataLength, \n"+
		"	CAST(isc.character_maximum_length AS VARCHAR )  as charLength, \n"+
		"	CAST ( isc.ordinal_position AS VARCHAR ) AS columnSeq, \n"+
		"	isc.is_nullable AS isNull, \n"+
		"	isc.character_set_name AS charset, \n"+
		"	isc.COLLATION_NAME AS collationName, \n"+
		"	ep.VALUE AS columnComment, \n"+
		"	isc.COLUMN_DEFAULT AS columnDefault \n"+
		"FROM \n"+
		"	INFORMATION_SCHEMA.COLUMNS isc \n"+
		"LEFT JOIN sys.columns sc \n"+
		"ON \n"+
		"	isc.column_name = sc.name AND sc.object_id = OBJECT_ID( isc.table_name ) \n"+
		"LEFT JOIN sys.extended_properties ep \n"+
		"ON \n"+
		"	ep.minor_id = sc.column_id AND ep.major_id = sc.object_id \n"+
		"where \n"+
		"	isc.table_schema in ('%s') and isc.TABLE_NAME in ('%s') \n"+
		"ORDER BY "+
		"	ordinal_position",
		parameter.Object.Schema, parameter.Object.Table))
	if result, err = forExecQuerySql(event, parameter, ETL.SMap, execSql); err != nil {
		err = ref.ErrAddPrintf("Meta", err)
		return
	}
	if result.Result == nil {
		return
	}
	var colRes []map[string]any
	for _, v := range result.Result.([]map[string]interface{}) {
		var vv = mapNullActive(v)
		if p, ok := vv["autoIncrement"]; ok {
			switch strings.ToLower(fmt.Sprintf("%v", p)) {
			case "auto_increment":
				vv["autoIncrement"] = true
			default:
				vv["autoIncrement"] = false
			}
		}
		for _, length := range []string{"dataLength", "charLength", "dataPrecision", "dataScale"} {
			if charLength, ok := vv[length]; ok {
				var carl int64
				if charLength == "NULL" {
					carl = 0
				} else {
					if carl, err = stringAnyToInt64(charLength); err != nil {
						err = ref.ErrAddPrintf("Meta", err)
						return
					}
				}
				vv[length] = carl
			}
		}
		vv["columnType"] = ExtractTypeName(fmt.Sprintf("%v", vv["dataType"]))
		colRes = append(colRes, vv)
		var dd = parDef.ColumnMeta{}
		if err = mapStringToStruct(vv, &dd); err != nil {
			err = ref.ErrAddPrintf("Meta", err)
			return
		}
		res = append(res, dd)
	}
	result.Result = res
	return
}
